package org.jili.novoland.game;

import org.jili.novoland.base.Actor;
import org.jili.novoland.base.Layer;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.Log;

public class BattleMap extends Layer implements Actor{
    public final static int DIRECT_EAST = 1;
    public final static int DIRECT_SOUTH = 2;
    public final static int DIRECT_WEST = 3;
    public final static int DIRECT_NORTH = 4;
    
    public final static int FIELD_CLASS = 1;
    public final static int FIELD_ROCK = 2;
    public final static int FIELD_WATER = 3;
    public final static int FIELD_TREE = 4;
    public final static int FIELD_MOVE = 5;
    public final static int moveCost[] = { 1, 1, 3, -1, 2 };

    private int rows = 0;
    private int cols = 0;
    private int[][] cellMatrix;
    private int[][] moveMatrix;

    private Bitmap img;
    private int numStaticTiles;
    private int[] srcTileX;
    private int[] srcTileY;

    public Bitmap getImg() {
        return img;
    }

    public BattleMap(int inTileWidth, int inTileHeight, Bitmap inImg,
            int inCols, int inRows) {
        // the specification doesn't states if the TiledLayer is visible on
        // creation
        // we assume it is

        super(inTileWidth, inTileHeight, inCols * inTileWidth, inRows
                * inTileHeight);
        if (inImg == null)
            throw new NullPointerException();

        int imageW = inImg.getWidth();
        int imageH = inImg.getHeight();

        if (inTileHeight <= 0 || inTileWidth <= 0 || imageW % inTileWidth != 0
                || imageH % inTileHeight != 0) {
            throw new IllegalArgumentException();
        }

        this.cols = inCols;
        this.rows = inRows;
        this.img = inImg;

        this.numStaticTiles = (imageW / inTileWidth) * (imageH / inTileHeight);

        this.cellMatrix = new int[inCols][inRows];
        this.moveMatrix = new int[inCols][inRows];
        clearMoveMatrix();
        this.srcTileX = new int[numStaticTiles + 1];
        this.srcTileY = new int[numStaticTiles + 1];
        int srcIndex = 1;
        for (int j = 0; j < imageH; j += getTileHeight()) {
            for (int i = 0; i < imageW; i += getTileWidth()) {
                this.srcTileX[srcIndex] = i;
//                Log.v(TiledLayer.class.getName(),
//                        Integer.toString(i) + "," + Integer.toString(j) + ","
//                                + Integer.toString(srcIndex));
                this.srcTileY[srcIndex] = j;
                srcIndex++;
            }
        }
    }

    public int getCell(int col, int row) {
        return this.cellMatrix[col][row];
    }

    public void setCell(int col, int row, int index) {
        synchronized (this) {
            if (index < 0 || index > numStaticTiles)
                throw new IndexOutOfBoundsException();
//            Log.v(TiledLayer.class.getName(), Integer.toString(row) + ","
//                    + Integer.toString(col));
            cellMatrix[col][row] = index;
        }
    }

    public void fillCells(int col, int row, int numCols, int numRows, int index) {
        synchronized (this) {
            if (numCols < 0 || numRows < 0)
                throw new IllegalArgumentException();
            if (row < 0 || col < 0 || col + numCols > this.cols
                    || row + numRows > this.rows)
                throw new IndexOutOfBoundsException();
            if (index < 0 || index > numStaticTiles)
                throw new IndexOutOfBoundsException();

            int rMax = row + numRows;
            int cMax = col + numCols;
            for (int r = row; r < rMax; r++) {
                for (int c = col; c < cMax; c++) {
                    cellMatrix[c][r] = index;
                }
            }
        }
    }

    public final int getCols() {
        return cols;
    }

    public final int getRows() {
        return rows;
    }


    public final void paint(int viewX, int viewY, Canvas g) {
        synchronized (this) {
            if (!this.isVisible())
                return;

            for (int i = 0; i < cols; i++) {
                for (int j = 0; j < rows; j++) {
                    int index = this.cellMatrix[i][j];
                    int count = this.moveMatrix[i][j];
                    if (index > 0)
                        paintTile(viewX, viewY, i, j, index, g);
                    if (count > 0)
                        paintTile(viewX, viewY, i, j, FIELD_MOVE, g);

                }
            }
        }
    }

    private void paintTile(int viewX, int viewY, int col, int row, int index, Canvas g) {
        // Log.v(TiledLayer.class.getName(),"index:" + Integer.toString(index));

        int srcX = srcTileX[index];
        int srcY = srcTileY[index];
        int dstX = viewX + col * getTileWidth();
        int dstY = viewY + row * getTileHeight();
        Rect srcRect = new Rect(srcX, srcY, srcX + getTileWidth(), srcY + getTileHeight());
        Rect dstRect = new Rect(dstX, dstY, dstX + getTileWidth(), dstY + getTileHeight());
        g.drawBitmap(img, srcRect, dstRect, null);

    }

    public void clearMoveMatrix() {
        for (int i = 0; i < cols; i++) {
            for (int j = 0; j < rows; j++) {
                moveMatrix[i][j] = -1;
            }
        }
    }

    public void setMoveMatrix(Role role) {
        clearMoveMatrix();
        int col = role.getCol();
        int row = role.getRow();
        int area = role.getAp(); // 有效范围

        moveMatrix[col][row] = 0; // 设定现在为移动0步

        for (int count = 0; count <= area - 1; count++) {
            for (int j = redressY(row - area); j < redressY(row + area + 1); j++) {
                for (int i = redressX(col - (area - Math.abs(row - j))); i <= redressX(col
                        + (area - Math.abs(row - j))); i++) {
                    if (i == 11 && j < 4){
                        Log.v("", "");
                    }
                    // 如果能够移动指定步数
                    if ((getMoveCount(i - 1, j) == count)
                            || (getMoveCount(i, j - 1) == count)
                            || (getMoveCount(i + 1, j) == count)
                            || (getMoveCount(i, j + 1) == count)) {
                        setMoveCount(i, j, count, area);
                    }
                }
            }
        }
//        for (int j = 0; j < rows; j++) {
//            String info = "";
//            for (int i = 0; i < cols; i++) {
//                String n = Integer.toString(moveMatrix[i][j]);
//                if (n.length() == 1)
//                    n = " " + n;
//                info = info + n + ", ";
//            }
//            Log.v("", info);
//        }

    }
    public  synchronized boolean setMoveList(int tcol, int trow, Role role) {
        int moveListCol[] = new int[role.getAp() + 1];
        int moveListRow[] = new int[role.getAp() + 1];
        for (int i = 0; i < role.getAp() + 1; i++) {
            moveListCol[i] = -1;
            moveListRow[i] = -1;
        }

        if (moveMatrix[tcol][trow] < 1) {
            return false;
        }
        while (moveMatrix[tcol][trow] > 0) {
            moveListCol[moveMatrix[tcol][trow]] = tcol;
            moveListRow[moveMatrix[tcol][trow]] = trow;

            int top = moveMatrix[tcol][trow - 1];
            int left = moveMatrix[tcol - 1][trow];
            int down = moveMatrix[tcol][trow + 1];
            int right = moveMatrix[tcol + 1][trow];

            if (moveMatrix[tcol][trow] - top == getCost(tcol, trow) && top > -1) {
                trow = trow - 1;
            } else if (moveMatrix[tcol][trow] - left == getCost(tcol, trow)   && left > -1) {
                tcol = tcol - 1;
            } else if (moveMatrix[tcol][trow] - down == getCost(tcol, trow)  && down > -1) {
                trow = trow + 1;
            } else if (moveMatrix[tcol][trow] - right == getCost(tcol, trow)  && right > -1) {
                tcol = tcol + 1;
            }
        }
        role.setMoveList(moveListCol, moveListRow);
        return true;
    }
    
    public int[][] getMoveMatrix() {
        return moveMatrix;
    }

    private synchronized int getMoveCount(int col, int row) {
        if ((col < 0) || (col > cols - 1) || (row < 0) || (row > rows - 1)) {
            // 无法移动返回-1
            return -1;
        }
        return moveMatrix[col][row];
    }

    private synchronized void setMoveCount(int col, int row, int count, int sp) {

        int cost = getCost(col, row);
        // 指定位置无法进入
        if (cost < 0) {
            return;
        }
        count = count + cost;
        // 移动步数超过移动能力
        if (count > sp) {
            return;
        }
        // 获得移动所需步数
        if ((moveMatrix[col][row] == -1) || (count < moveMatrix[col][row])) {
            moveMatrix[col][row] = count;
        }
    }

    public int getCost(int col, int row) {
        return moveCost[cellMatrix[col][row]];
    }

    private int redressX(int col) {
        if (col < 0)
            col = 0;
        if (col > cols - 1)
            col = cols - 1;
        return col;
    }

    private int redressY(int row) {
        if (row < 0)
            row = 0;
        if (row > rows - 1)
            row = rows - 1;
        return row;
    }

    @Override
    public void tick() {
        // TODO Auto-generated method stub
        
    }
}
